import React, { memo, useCallback, useReducer } from "react";

interface State {
  count: number;
  name: string;
  price: number;
}

type ActionType = "increment" | "decrement";

type Action = {
  type: ActionType;
  payload?: Partial<State>;
}

const initState: State = {
  count: 0,
  name: "name",
  price: 10,
};

const reducer = (state: State, action: Action) => {
  switch (action.type) {
    case "increment":
      return { ...state, count: state.count + 1 };
    case "decrement":
      return { ...state, count: state.count - 1 };
    default: {
      return state;
    }
  }
};

/**
 * useReducer
 * 模式：订阅发布模式、命令模式
 * 场景：单组件内部，复杂状态变更
 * 缺点：数据对象变更导致视图重新渲染问题。 （使用 immer 解决）
 */
export const Basic = memo(() => {
  /**
   * 订阅：元素 props
   * 发布：分散发布 setCount、setName、setPrice
   * 问题：关注点分离

    const [count, setCount] = useState(() => 0);
    const [name, setName] = useState(() => "name");
    const [price, setPrice] = useState(() => 10);

    const handleIncrement = useCallback(() => {
      setCount((count) => count + 1);
    }, []);

    const handleDecrement = useCallback(() => {
      setCount((count) => count - 1);
    }, []);

   * 订阅：元素 props
   * 发布：一个 dispatch
   * 问题：组件职责不单一，逻辑分散 - 具名操作

    const [order, setOrder] = useState(() => ({
      count: 0,
      name: "name",
      price: 10,
    }));

    const handleIncrement = useCallback(() => {
      setOrder((o) => ({ ...o, count: o.count + 1 }));
    }, []);
   */

  /**
   * 订阅：元素 props
   * 发布 dispatch、操作 action、状态变化逻辑 reducer
   * 问题：数据没有响应式变化 - immer
   */
  const [store, dispatch] = useReducer(reducer, initState);

  const handleIncrement = useCallback(() => {
    dispatch({ type: "increment" });
  }, []);

  const handleDecrement = useCallback(() => {
    dispatch({ type: "decrement", payload: { count: 10 } });
  }, []);

  return (
    <div>
      <h1>useReducer</h1>
      <p>{store.count}</p>
      <p>{store.name}</p>
      <p>{store.price}</p>
      <button onClick={handleIncrement}>+increment</button>
      <button onClick={handleDecrement}>-decrement</button>
    </div>
  );
});
